﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace TaoDingPvServer.Network
{
    public class WebsocketProtocol
    {
        public byte[] BuildFrame(int OpCode, byte[] Data)
        {
            byte[] fragment;

            if (Data.Length < 126)
            {
                fragment = new byte[2 + Data.Length];
                fragment[1] = (byte)Data.Length;
            }
            else if (Data.Length < 65536)
            {
                fragment = new byte[4 + Data.Length];
                fragment[1] = 126;
                fragment[2] = (byte)(Data.Length / 256);
                fragment[3] = (byte)(Data.Length % 256);
            }
            else
            {
                fragment = new byte[10 + Data.Length];
                fragment[1] = 127;

                int left = Data.Length;
                int unit = 256;

                for (int i = 9; i > 1; i--)
                {
                    fragment[i] = (byte)(left % unit);
                    left = left / unit;
                    if (left == 0)
                    {
                        break;
                    }
                }
            }

            fragment[0] = (byte)((byte)OpCode | 0x80);

            if (Data.Length > 0)
            {
                Buffer.BlockCopy(Data, 0, fragment, fragment.Length - Data.Length, Data.Length);
            }

            return fragment;
        }
        //false:继续接收数据 true:继续解析数据
        public bool GetFrame(List<byte> Buffer, out RFC6455Frame Frame)
        {
            Frame = null;
            //数据不足
            if (Buffer.Count < 2)
            {
                return false;
            }
            //获取数据
            int DataLen = Buffer[1] & 0x7F;
            int DataOffset = 0;
            if (DataLen < 126)
            {
                DataOffset = 2;
            }
            else if (DataLen == 126)
            {
                if (Buffer.Count < 4)
                {
                    return false;
                }
                DataLen = (Buffer[2] << 8) + Buffer[3];
                DataOffset = 4;
            }
            else if (DataLen == 127)
            {
                if (Buffer.Count < 10)
                {
                    return false;
                }
                DataLen = Buffer[9] + (Buffer[8] << 8) + (Buffer[7] << 16) + (Buffer[6] << 24);//四个字节足够大了，忽略其他四个字节
                DataOffset = 10;
            }

            //MaskKey-服务端接收一般都包括此内容
            byte[] key = new byte[4];
            bool bMask = (Buffer[1] & 0x80) == 0x80;
            if (bMask)
            {
                for (int i = 0; i < 4; i++)
                {
                    key[i] = Buffer[DataOffset + i];
                }
                DataOffset += 4;
            }

            if (Buffer.Count >= DataOffset + DataLen)
            {
                Frame = new RFC6455Frame();
                Frame.Fin = (Buffer[0] & 0x80) >> 7;
                Frame.OpCode = Buffer[0] & 0x0f;
                Frame.Data = new byte[DataLen];
                for (int i = 0; i < DataLen; i++)
                {
                    Frame.Data[i] = Buffer[DataOffset + i];
                }
                if (bMask)
                {
                    for (int i = 0; i < DataLen; i++)
                    {
                        Frame.Data[i] = (byte)(Frame.Data[i] ^ key[i & 0x03]);
                    }
                }
                Buffer.RemoveRange(0, DataOffset + DataLen);
            }
            else
            {
                return false;
            }
            //判断接下来是继续解析还是接收数据    
            if (Buffer.Count > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool GetHandshakeFrame(List<byte> Buffer, out Dictionary<string, string> HandshakeData)
        {
            string s = Encoding.UTF8.GetString(Buffer.ToArray());
            StringReader reader = new StringReader(s);
            //解析接收到的数据
            HandshakeData = new Dictionary<string, string>();
            while (true)
            {
                string line = reader.ReadLine();
                if (line == null)
                {
                    break;
                }
                line = line.Replace(" ", "");

                string[] lineContents = line.Split(new char[] { ':' });
                string key = lineContents[0].ToLower();
                if (lineContents.Length > 1)
                {
                    HandshakeData[key] = lineContents[1];
                }
                else
                {
                    HandshakeData[key] = "";
                }
            }
            //判断是否包含握手帧需要的key
            if (!HandshakeData.ContainsKey("get/http/1.1"))
            {
                return false;
            }
            if (!HandshakeData.ContainsKey("upgrade"))
            {
                return false;
            }
            if (!HandshakeData.ContainsKey("connection"))
            {
                return false;
            }
            if (!HandshakeData.ContainsKey("sec-websocket-key"))
            {
                return false;
            }
            if (!HandshakeData.ContainsKey("sec-websocket-version"))
            {
                return false;
            }
            Buffer.Clear();
            return true;
        }

    }

    public class RFC6455Frame
    {
        public int Fin;
        public int OpCode;
        public byte[] Data;
    }
}
